package org.insia.smartposse.dao;

import java.io.Serializable;
import java.util.List;

import org.apache.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.Projections;
import org.insia.smartposse.idao.IGenericDAO;

/**
 * Generic DAO class.
 *
 * @author sok hout
 * @version 1.02
 * @param <T> Class type.
 * @param <PK> Primary key type.
 */
public class GenericDAO<T, PK extends Serializable> 
implements IGenericDAO<T, PK> {
	protected static final Object mutex = new Object();
	protected static Session _SESSION;
	protected static final Logger _LOG = Logger.getLogger(GenericDAO.class);
	/**
	 * The type of class for the generic type.
	 */
	protected Class type;
	
	/**
	 * Empty construtor
	 *
	 */
	public GenericDAO() {
	}

	/*
	 * (non-Javadoc)
	 * @see org.insia.smartposse.idao.IGenericDAO#copy(java.lang.Object)
	 */
	@SuppressWarnings("unchecked")
	public PK copy(T obj) throws Exception {
		synchronized (mutex) {
			PK rst = null;
			rst = (PK)_SESSION.save(obj);
			return rst;
		}
	}

	/*
	 * (non-Javadoc)
	 * @see org.insia.smartposse.idao.IGenericDAO#count()
	 */
	public long count() throws Exception {
		synchronized (mutex) {
			long rst = 0;
			Criteria crit = _SESSION.createCriteria(type);
			crit.setProjection(Projections.rowCount());
			rst = Long.parseLong(crit.list().get(0).toString());
			return rst;
		}
	}

	/*
	 * (non-Javadoc)
	 * @see org.insia.smartposse.idao.IGenericDAO#create(java.lang.Object)
	 */
	@SuppressWarnings("unchecked")
	public PK create(T obj) throws Exception {
		synchronized (mutex) {
			PK rst = null;
			rst = (PK)_SESSION.save(obj);
			return rst;
		}
	}

	/*
	 * (non-Javadoc)
	 * @see org.insia.smartposse.idao.IGenericDAO#delete(java.lang.Object)
	 */
	public void delete(T obj) throws Exception {
		synchronized (mutex) {
			_SESSION.delete(obj);
		}
	}

	/*
	 * (non-Javadoc)
	 * @see org.insia.smartposse.idao.IGenericDAO#get(java.io.Serializable)
	 */
	@SuppressWarnings("unchecked")
	public T get(PK id) throws Exception {
		synchronized (mutex) {
			T rst = null;
			rst = (T) _SESSION.get(type, id);
			return rst;
		}
	}

	/*
	 * (non-Javadoc)
	 * @see org.insia.smartposse.idao.IGenericDAO#getList()
	 */
	@SuppressWarnings("unchecked")
	public List<T> getList() throws Exception {
		synchronized (mutex) {
			List<T> rst = null;
			Criteria crit = _SESSION.createCriteria(type);
			rst = (List<T>)crit.list();
			return rst;
		}
	}

	/*
	 * (non-Javadoc)
	 * @see org.insia.smartposse.idao.IGenericDAO#getList(int)
	 */
	@SuppressWarnings("unchecked")
	public List<T> getList(int start) throws Exception {
		synchronized (mutex) {
			List<T> rst = null;
			Criteria crit = _SESSION.createCriteria(type.getClass());
			crit.setFirstResult(start);
			rst = (List<T>)crit.list();
			return rst;
		}
	}

	/*
	 * (non-Javadoc)
	 * @see org.insia.smartposse.idao.IGenericDAO#getList(int, int)
	 */
	@SuppressWarnings("unchecked")
	public List<T> getList(int start, int end)
	throws Exception {
		synchronized (mutex) {
			List<T> rst = null;
			Criteria crit = _SESSION.createCriteria(type);
			crit.setFirstResult(start);
			crit.setMaxResults(end-start);
			rst = (List<T>)crit.list();
			return rst;
		}
	}

	/*
	 * (non-Javadoc)
	 * @see org.insia.smartposse.idao.IGenericDAO#getListPerPage(int, int)
	 */
	public List<T> getListPerPage(int nbPerPage, int numPage)
	throws Exception {
		return getList(nbPerPage*numPage, nbPerPage*(numPage+1));
	}

	/*
	 * (non-Javadoc)
	 * @see org.insia.smartposse.idao.IGenericDAO#update(java.lang.Object)
	 */
	public void update(T obj)
	throws Exception {
		synchronized (mutex) {
			_SESSION.update(obj);
		}
	}

	/**
	 * Set the hibernate session used by Generic DAO.
	 * @return
	 */
	public static Session get_SESSION() {
		return _SESSION;
	}

	/**
	 * Return the hibernate session used by Generic DAO.
	 * @param session
	 */
	public static void set_SESSION(Session session) {
		_SESSION = session;
	}

}
